fs = require "fs"
path = require "path"
uuid = require "uuid"
fsAsync = require "fsAsync"
{Dao} = require "../dao/Dao"

ResFile = require "../util/ResFile"

exports.Srv = new Class(
  Implements: [Events, Options]
  #session会话
  session: {}
  #保存当前会话的状态
  _state:
    download:{}
    _reqTimeout: {}
  options:
    #订阅消息推送编码
    #_sbcptUid: undefined
    #本类的名称sys.MenuSrv
    srvPath: "Srv"
    #本类对应的Dao
    dao: null
  initialize: (options) ->
    t = this
    t.setOptions options
    t
  onDraw: ->
    t = this
    o = t.options
    o.dao = Dao.getInstance()
    t.escapeId = o.dao.escapeId
    t.crtTmpTab = o.dao.crtTmpTab
    t.drpTmpTab = o.dao.drpTmpTab
    t
  #外界主动清除session
  _clearSession: (reqOpt)->
    t = this
    o = t.options
    session = t.session
    if session isnt undefined and session._sess_time isnt undefined
      clearTimeout session._sess_time
    if reqOpt._sid
      delete t._srvFactory[reqOpt._sid]
    ""
  #页面关闭,释放内存_state
  closeSrv: (reqOpt)->
    t = this
    o = t.options
    delete t._srvFactory[reqOpt._sid][reqOpt.srvKey] if reqOpt._sid and t._srvFactory[reqOpt._sid]
    ""
  #sp存储过程名称,spArg存储过程参数,rsNum存储过程返回的结果集个数
  callSp: (reqOpt,sp,spArg,rsNum) ->
    t = this
    o = t.options
    dao = o.dao
    rltSet = yield dao.callSp reqOpt,sp,spArg,rsNum
    rltSet
  callSql: (reqOpt,sql,spArg,rsNum)->
    t = this
    o = t.options
    throw new Error "Srv.callSql the first argument must be reqOpt!" if !reqOpt or reqOpt.reqOpt_ibmkx5s8 isnt true
    rss = yield o.dao.callSql reqOpt,sql,spArg,rsNum
    rss
  getConn: (reqOpt)->
    t = this
    o = t.options
    o.dao.getConn reqOpt
  endConn: (reqOpt)->
    t = this
    o = t.options
    o.dao.endConn reqOpt
  destroyConn: (reqOpt)->
    t = this
    o = t.options
    o.dao.destroyConn reqOpt
  beginTran: (reqOpt)->
    t = this
    o = t.options
    o.dao.beginTran reqOpt
  commitTran: (reqOpt)->
    t = this
    o = t.options
    o.dao.commitTran reqOpt
  rollbackTran: (reqOpt)->
    t = this
    o = t.options
    o.dao.rollbackTran reqOpt
  setAutoCommit: (reqOpt)->
    t = this
    o = t.options
    o.dao.setAutoCommit reqOpt
  _sessionId: ->
    t = this
    o = t.options
    _sid = uuid.v4()
    _sid
  "@imgInput":{comment:"图片上传控件"}
  imgInput: (reqOpt,file)->
    t = this
    o = t.options
    uid = yield t.buf2uid reqOpt,file.path,file.name
    uid
  "@buf2uid":{comment:"把需要下载的文件或buffer转为uid",_private: true}
  buf2uid: (reqOpt,buf,name,callback)->
    t = this
    uid = String.uniqueID()
    if typeOf(buf) is "string"
      t._state.download[uid] = {buffer:buf,name:name,callback:callback}
      return uid
    buf = yield fsAsync.readFileAsync buf
    tmpFileName = yield Util.writeTmpFile buf
    t._state.download[uid] = {name:name,buffer:tmpFileName,callback:callback}
    uid
  "@uid2buf":{comment:"把uid转为需要下载的文件的路径",_private: true}
  uid2buf: (uid)->
    return uid if !uid
    rvObj = this._state.download[uid]
    return uid if !rvObj
    rvObj.buffer
  #通过uid下载文件
  downloadByUid: (reqOpt,uid,attachment)->
    t = this
    o = t.options
    res = reqOpt.res
    req = reqOpt.req
    reqOpt.res_auto_end = false
    if uid is null or uid is undefined or uid.trim() is ""
      res.end()
      return
    download = t._state.download
    path2 = download[uid].buffer
    remove = download[uid].remove
    gzip = download[uid].gzip
    attachment = download[uid].attachment or "attachment"
    hrow "attachment must be attachment or inline!" if attachment isnt "attachment" and attachment isnt "inline"
    throw req.url if path2 is undefined or path2 is null
    name = download[uid].name or "download"
    #中文文件名乱码问题
    name = encodeURIComponent name
    extname = path.extname(name).substring 1
    if extname
      extname = extname.toLowerCase()
      res.setHeader "Content-Type", ResFile.mime[extname] if ResFile.mime[extname]
    res.setHeader "Content-Disposition",attachment+"; filename="+name+"; charset=UTF-8"
    throw "t._state.download path2 cannot be buffer! it must be string!" if typeOf(path2) isnt "string"
    #Content-Encoding  ctEn
    if attachment is "inline" and gzip isnt false
      buffer2 = yield fsAsync.readFileAsync path2
      gf = yield ResFile.gzipFn req.headers["accept-encoding"],extname,buffer2
      buffer2 = gf.zipBuf
      ctEn = gf.zipType
      ResFile.md5Etag buffer2,ctEn,req,res
    else
      pmTmp = new Promise (resolve,reject)->
        readstream = fs.createReadStream path2
        readstream.on "data",(chunk)->
          res.write chunk
          return
        readstream.on "end",->
          res.end()
          resolve()
          return
        readstream.on "error",(err)->
          reject err
          return
        return
      yield pmTmp
    callback = download[uid].callback
    if callback
      yield callback path2
    if remove is true
      delete download[uid]
    return
  #清空缓存
  _clearCache: (reqOpt,uid)->
    throw "_clearCache is not defined!" if uid isnt "b2730998-8286-469c-ac16-97757ff76956"
    keys = Object.keys require.cache
    outKeyArr = ["/dao/","/node_modules/","/node-inspector/"]
    for key in keys
      keyTmp = key.replace /\\/gm,"/"
      has = false
      for outKey in outKeyArr
        if keyTmp.indexOf(outKey) isnt -1
          has = true
          break
      if !has
        console.log key
        delete require.cache[key]
    "success"
  #执行srv的方法
  "@_applyMd":{_private: true}
  _applyMd: (reqOpt,mdStr,pms)->
    t = this
    o = t.options
    srvPath = reqOpt.srvPath
    console.log ""
    console.log srvPath+"."+mdStr
    o.srvPath = srvPath
    reqOpt.mdStr = mdStr
    reqOpt.pms = pms
    uid = undefined
    rqt = t._state._reqTimeout
    aMdObj = t["@"+mdStr]
    if mdStr is "_reqTimoutByUid"
      uid = pms[0]
      throw "_reqTimoutByUid pms[0] must be string" if uid is undefined
      tk = rqt[uid]
      tk = "" if tk is undefined
    else
      method = t[mdStr]
      throw srvPath+" has not method "+mdStr if method is undefined
      throw srvPath+"/"+mdStr+" is _private" if aMdObj isnt undefined and aMdObj._private is true
      throw srvPath+"/"+mdStr+" is protected" if (method.$origin and method.$origin.$protected is true) or method.$protected is true
      if pms isnt undefined
        pmsType = typeOf pms
        if pmsType isnt "array" and pmsType isnt "arguments"
          pms = [reqOpt,pms]
        else
          pms.unshift reqOpt
      else
        pms = [reqOpt]
      tk = method.apply t,pms
      return tk if !co.isGenerator(tk) and !co.isPromise tk
      #开启事务
      if aMdObj and aMdObj.isTran
        reqOpt.isTran = true
        yield t.getConn reqOpt
        try
          yield t.beginTran reqOpt
        catch er2
          t.endConn reqOpt
          throw er2
    tmk = undefined
    isTimeout = false
    taskTm = new Promise (resolve,reject)->
      tmk = setTimeout(->
        isTimeout = true
        resolve()
        return
      ,60000)
      return
    rv = yield Promise.race [taskTm,co(tk)]
    clearTimeout tmk if tmk isnt undefined
    if isTimeout
      uid = String.uniqueID() if uid is undefined
      reqOpt.action = ["_reqTimoutByUid",uid]
      rqt[uid] = tk
      return ""
    delete rqt[uid]
    if !aMdObj or aMdObj.autoDropTmpTable isnt false
      yield t.drpTmpTab reqOpt
    #提交事务
    yield t.commitTran reqOpt
    rv
)
